package com.tdcy.sys.util.wx;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tdcy.framework.exception.QuickuException;
import com.tdcy.framework.util.ExceptionUtils;
import com.tdcy.framework.util.StringUtils;
import com.tdcy.framework.util.SysUtils;
import com.tdcy.framework.util.TaskController;
import com.tdcy.sys.dao.eo.WxInfLogEO;
import com.tdcy.sys.util.ParamUtils;
import com.tdcy.sys.util.SeqUtils;

public class WxUtils {
	private static Logger log = LoggerFactory.getLogger(WxUtils.class);
	private static final int CODE_LENGTH = 32;// 字符串长度
	private static final String RAND_RANGE = "1234567890ABCDEFGHIJKLMNUVWXYZ";// 随机字符串范围
	private static final char[] CHARS = RAND_RANGE.toCharArray();// 随机字符串范围
	private static Random random = new Random();

	public static String getCertPath() throws IllegalAccessException {
		return SysUtils.getWebInfPath() + File.separator + "wx" + File.separator + "wx.cert";
	}

	public static String getCertPass() {
		return ParamUtils.getParamValue("wx_cert_pass", ParamUtils.getWxMchId());
	}

	public static String getlocalIp() {
		String ip = null;
		Enumeration allNetInterfaces;
		try {
			allNetInterfaces = NetworkInterface.getNetworkInterfaces();
			while (allNetInterfaces.hasMoreElements()) {
				NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
				List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();
				for (InterfaceAddress add : InterfaceAddress) {
					InetAddress Ip = add.getAddress();
					if (Ip != null && Ip instanceof Inet4Address) {
						ip = Ip.getHostAddress();
					}
				}
			}
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ip;
	}

	/**
	 * 获取随机串
	 */
	public static String getNonceStr() {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < CODE_LENGTH; i++)
			sb.append(CHARS[random.nextInt(CHARS.length)]);
		return sb.toString();
	}

	/**
	 * 获取时间戳
	 * 
	 * @return
	 */
	public static String getTimestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}

	/**
	 * 签名串
	 * 
	 * @param paraMap
	 * @return
	 */
	public static String getSign(Map<String, String> map, String apiKey) {
		Map<String, String> sortMap = new TreeMap<String, String>();
		sortMap.putAll(map);

		Set<String> keySet = sortMap.keySet();
		List<String> strList = new ArrayList<String>();
		for (String key : keySet) {
			String value = sortMap.get(key);
			if (!StringUtils.isEmpty(key)) {
				strList.add(key + "=" + value);
			}
		}

		strList.add("key=" + apiKey);
		String sign = MD5.MD5Encode(StringUtils.join(strList, "&")).toUpperCase();
		return sign;
	}

	public static String getSign2(Map<String, String> map, String apiKey) {
		ArrayList<String> list = new ArrayList<String>();
		for (Map.Entry<String, String> entry : map.entrySet()) {
			if (entry.getValue() != "") {
				list.add(entry.getKey() + "=" + entry.getValue() + "&");
			}
		}
		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		String result = sb.toString();
		result += "key=" + apiKey;
		System.out.println(result);
		// Util.log("Sign Before MD5:" + result);
		result = MD5.MD5Encode(result).toUpperCase();
		// Util.log("Sign Result:" + result);
		return result;
	}

	/**
	 * 转换map to xml
	 * 
	 * @param map
	 * @return
	 */
	public static String mapToXml(Map<String, String> map) {
		Map<String, String> sortMap = new TreeMap<String, String>();
		sortMap.putAll(map);

		Set<String> keySet = sortMap.keySet();

		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
		sb.append("<xml>\r\n");
		for (String key : keySet) {
			String value = sortMap.get(key);
			if (!StringUtils.isEmpty(key)) {
				sb.append("<" + key + "><![CDATA[" + value + "]]></" + key + ">\r\n");
			}
		}
		sb.append("</xml>\r\n");
		return sb.toString();
	}

	public static Map<String, String> xmlToMap(String xml) {
		try {
			xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + xml;

			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();

			SAXReader reader = new SAXReader();
			Reader read = new InputStreamReader(new ByteArrayInputStream(xml.getBytes()), "UTF-8");
			org.dom4j.Document doc = reader.read(read);

			Map<String, String> resultMap = new HashMap<String, String>();
			Element root = doc.getRootElement();
			List<Element> eles = root.elements();
			for (Element e : eles) {
				resultMap.put(e.getName(), e.getText());
			}
			return resultMap;
		} catch (Exception e) {
			e.printStackTrace();
			throw new QuickuException("解析参数出错", e);
		}
	}

	public static Map<String, String> post(String infName, String url, Map<String, String> paraMap, boolean needCert) {
		try {
			HttpsRequest request = new HttpsRequest();
			String xml = mapToXml(paraMap);

			log.debug("sendXml:" + xml);

			String result = request.sendPost(url, xml, needCert);

			log.debug("resultXml:" + xml);

			Map<String, String> resultMap = xmlToMap(result);

			String return_code = resultMap.get("return_code");
			String return_msg = resultMap.get("return_msg");
			String result_code = resultMap.get("result_code");
			String err_code = resultMap.get("err_code");
			String err_code_des = resultMap.get("err_code_des");

			// 接口调用记录
			WxInfLogEO logeo = new WxInfLogEO();
			logeo.setWxInfId(SeqUtils.getMaxNo("wx_inf_id"));
			logeo.setErrCode(err_code);
			logeo.setErrCodeDes(err_code_des);
			logeo.setInfName(infName);
			logeo.setRequestXml(xml);
			logeo.setResultCode(result_code);
			logeo.setResultXml(result);
			logeo.setReturnCode(return_code);
			logeo.setReturnMsg(return_msg);
			AddWxInfLogThread at = new AddWxInfLogThread();
			at.setEo(logeo);
			TaskController.execute(at);

			if ("fail".equalsIgnoreCase(return_code)) {
				throw new QuickuException(return_msg);
			}

			if ("fail".equalsIgnoreCase(result_code)) {
				String message = err_code_des;
				if (StringUtils.isEmpty(message)) {
					message = WxErrors.getErrorMsg(err_code);
				}

				throw new QuickuException(message);
			}

			String sign = paraMap.get("sign");
			if (StringUtils.isEmpty(sign)) {
				throw new QuickuException("sign不能为空");
			}
			paraMap.remove("sign");

			String checksign = WxUtils.getSign(paraMap, ParamUtils.getWxApiSecretkey());
			if (!sign.equals(checksign)) {
				throw new QuickuException("验证签名失败	");
			}

			return resultMap;
		} catch (Exception e) {
			log.error("exception:" + ExceptionUtils.getThrowableStr(e));
			if (e instanceof QuickuException) {
				throw (QuickuException) e;
			} else {
				throw new QuickuException("调用微信支付(" + url + ")异常", e);
			}

		}
	}

	public static void main(String[] args) {
		// Map<String, String> m = new HashMap<String, String>();
		// m.put("appid", "wxf6a19f140f3e9144");
		// m.put("mch_id", "1304976901");
		String apikey = "nRceeQ16lpmAkVfPj9s62T0h06UWYe2n";
		String apikey2 = "6cFPsrZriuTVK2sNWDqUyogJtkML6y1H";
		// m.put("nonce_str", "NGDMFD36DWCNC0WUFLD4VLLHCDNMY4HX");
		// m.put("body", "健康产品订单微信扫码支付");
		// m.put("notify_url", "http://wx_pay_notify");
		// m.put("out_trade_no", "00082CG34D350083");
		// m.put("product_id", "00082CG34D350083");
		// m.put("spbill_create_ip", "192.168.1.3");
		// m.put("total_fee", "22000");
		// m.put("trade_type", "NATIVE");
		//
		// System.out.println(getSign(m, apikey));
		// System.out.println(getSign2(m, apikey));
		//
		// String ss =
		// "appid=wxf6a19f140f3e9144&body=健康产品订单微信扫码支付&mch_id=1304976901&nonce_str=1YWY7IXAZVVJ7GXM45LHDCI5FD1WFAG4&notify_url=http://wx_pay_notify&out_trade_no=00082CG34D350083&product_id=00082CG34D350083&spbill_create_ip=192.168.1.3&total_fee=22000&trade_type=NATIVE&key=nRceeQ16lpmAkVfPj9s62T0h06UWYe2n";
		// String sign = MD5.MD5Encode(ss).toUpperCase();

		String param = "<xml><appid><![CDATA[wx1d01ee0ea40c51fc]]></appid><bank_type><![CDATA[CCB_DEBIT]]></bank_type><cash_fee><![CDATA[1]]></cash_fee><device_info><![CDATA[868014024986038]]></device_info><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[N]]></is_subscribe><mch_id><![CDATA[1318320401]]></mch_id><nonce_str><![CDATA[e8fd4a8a5bab2b3785d794ab51fef55c]]></nonce_str><openid><![CDATA[oK3y5wUpo5qw-hORSY0o3vi0R3zs]]></openid><out_trade_no><![CDATA[00042IG36K493805]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[D9715343A3DD2CCD8845843FB4C91B40]]></sign><time_end><![CDATA[20160326204952]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[APP]]></trade_type><transaction_id><![CDATA[4005672001201603264304554638]]></transaction_id></xml>";
		Map<String, String> paraMap = WxUtils.xmlToMap(param);
		String sign = paraMap.get("sign");
		System.out.println("sign:" + sign);
		paraMap.remove("sign");
		System.out.println(paraMap);

		String checksign = WxUtils.getSign(paraMap, apikey2);

		System.out.println("checksign:" + checksign);

	}

}
